package edu.hawaii.halealohacli.jcev.processor;

import java.util.Map;
import java.util.TreeMap;
import org.wattdepot.client.WattDepotClient;
import edu.hawaii.halealohacli.jcev.command.Command;
import edu.hawaii.halealohacli.jcev.command.CurrentPower;
import edu.hawaii.halealohacli.jcev.command.DailyEnergy;
import edu.hawaii.halealohacli.jcev.command.EnergySince;
import edu.hawaii.halealohacli.jcev.command.Help;
import edu.hawaii.halealohacli.jcev.command.MonitorPower;
import edu.hawaii.halealohacli.jcev.command.Quit;
import edu.hawaii.halealohacli.jcev.command.RankTowers;
import edu.hawaii.halealohacli.jcev.command.SetBaseline;
import edu.hawaii.halealohacli.jcev.command.MonitorGoal;


/**
 * Processes the commands from the Command Line Interface and executes them if they are valid.
 * 
 * @author Christopher Foo
 * 
 */
public class CommandProcessor {

  /**
   * A map containing all valid commands that the user can enter. The key is the command name and
   * the value is the command object.
   */
  private Map<String, Command> commands;

  private Map<String, Double> baseline;
  
  /**
   * Creates a new CommandProcessor object and initializes it.
   */
  public CommandProcessor() {
    this.commands = this.generateMap();
  }
  
  /**
   * Returns the map containing the command-name => command-object pairs.
   * @return A defensively copied version of the commands map.
   */
  public Map<String, Command> getCommands() {
    
    //Defensive Copy
    return new TreeMap<String, Command> (this.commands);
  }

  /**
   * Creates the commands Map with the hard-coded name-command pairs.
   * 
   * @return A Map containing the name-command pairs of each valid command.
   */
  private Map<String, Command> generateMap() {
    TreeMap<String, Command> map = new TreeMap<String, Command>();
    
    //To add a new command:
    //map.put("command-name", new CommandObject());
    map.put("current-power", new CurrentPower());
    map.put("daily-energy", new DailyEnergy());
    map.put("energy-since", new EnergySince());
    map.put("rank-towers", new RankTowers());
    map.put("set-baseline", new SetBaseline());
    map.put("monitor-goal", new MonitorGoal());
    map.put("monitor-power", new MonitorPower());
    map.put("help", new Help(map));
    map.put("quit", new Quit());
    return map;
  }

  /**
   * Executes the command with the given commandName if it is a valid command with the given
   * arguments string.
   * 
   * @param client The WattDepotClient connected to the WattDepot server.
   * @param commandName The name of the command to be executed.
   * @param arguments The arguments the command should be executed with.
   * @throws ExitException If the quit command is executed.
   * @throws Exception If invalid command is called.
   */
  public void execute(WattDepotClient client, String commandName, String arguments)
      throws ExitException, Exception {
    Command command = this.commands.get(commandName);
    if (command == null) {
      throw new Exception("Error: \"" + commandName + "\" is an invalid command!  Try \"help\""
                          + " for a list of valid commands.");
    }
    else if ("set-baseline".equals(commandName)) {
      try {
        SetBaseline sb = new SetBaseline();
        sb.execute2(arguments, client, baseline);
        this.baseline = sb.getBaselineData();
      }
      catch (Exception e) {
        System.err.println(e);
      }
    }
    else if ("monitor-goal".equals(commandName)) {
    
    if (this.baseline == null) {
       throw new Exception("Error: Baselines have not been set. baseline command must be"
        + " executed first before this command.");
        }

        try {
          MonitorGoal mg = new MonitorGoal();
          mg.executeMG(arguments, client, this.baseline);
         }
         catch (Exception e) {
         System.err.println(e);  
        }
       }

    else {
      try {
        command.execute(arguments, client);
      }
      catch (ExitException e) {
        System.out.println(e.getMessage());
        //Pass exit exception to the next level (Command)
        throw e;
      }
      catch (Exception e) {
        System.out.println(e.getMessage());
      }
    }
  }
}
